#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define QLEN 10

#ifndef HOST_NAME_MAX
#define  HOST_NAME_MAX 256
#endif

extern int initserver(int, const struct sockaddr *, socklen_t, int);

void serve(int sockfd) {
    int clfd, status;
    pid_t pid;
    set_cloexec(sockfd);
    fflush(NULL);
    for (;;) {
        if ((clfd= accept(sockfd, NULL, NULL)) < 0) {
            syslog(LOG_ERR, "practice_16.6: accept error: %s", strerror(errno));
            exit(1);
        }
        if ((pid= fork()) < 0) {
            syslog(LOG_ERR, "practice_16.6: fork error: %s", strerror(errno));
            exit(1);
        } else if (pid == 0) {
            if (dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO ||
                dup2(clfd, STDERR_FILENO) != STDERR_FILENO) {
                syslog(LOG_ERR, "practice_16.6: unexpected error");
                exit(1);
            }
            //dont worry clfd = stdin as daemonize make it open to /dev/null
            close(clfd);
            execl("/usr/bin/uptime", "uptime", NULL);
            syslog(LOG_ERR, "practice_16.6: unexpected return from exec: %s", strerror(errno));
            exit(1);
        } else {
            close(clfd);
            waitpid(pid, &status, 0);
        }
    }
}

int main(int argc, char *argv[]) {
    struct sockaddr_in addr;
    int sockfd;
    
    memset(&addr, 0, sizeof(addr));
    addr.sin_family= AF_INET;
    addr.sin_port= htons(8080);
    addr.sin_addr.s_addr= INADDR_ANY;

    daemonize("ruptimed");
    if ((sockfd= initserver(SOCK_STREAM, (const struct sockaddr *)&addr, sizeof(addr), QLEN)) >= 0) {
        serve(sockfd);
        exit(0);
    }
    syslog(LOG_ERR, "initserver error: %s", strerror(errno));
    exit(1);
}
